/* 
 * Cashbox is the legal property of its developers, whose names are listed in the copyright file included
 * with this source distribution.
 * 
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
 * General Public License as published by the Free Software Foundation; either version 2 of the License,
 * or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
 * Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with this program; if not,
 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#import "CBSetupAssistantWindowController.h"

#import "CBImportPanelController.h"
#import "CBImporter.h"
#import "CB50Importer.h"
#import "CBImportViewController.h"

#import "CBAccount.h"

#import <Cashbox/CBAccountControllerProtocol.h>

#define DONATION_URL			@"http://www.fadingred.org/donations/"

#define WELCOME_INDEX			0
#define ADD_ACCOUNTS_INDEX		1
#define IMPORT_OHTER_INDEX		2
#define IMPORT_CB50_INDEX		3
#define COMPLETE_INDEX			5

@interface CBSetupAssistantWindowController (Private)

- (id)initWithDeleagte:(id)delegate
		didEndSelector:(SEL)didEndSelector
	didDismissSelector:(SEL)didDismissSelector;


- (BOOL)releaseWhenComplete;
- (void)setReleaseWhenComplete:(BOOL)flag;
- (void)runSetupAssistant;
- (void)finishRuningSeuptAssistant;

- (void)addAccount:(NSError **)error;

- (void)showProgress:(float)percent withTitle:(NSString *)title;
- (void)hideProgress;

- (IBAction)activateWelcome:(id)sender;
- (BOOL)completeWelcome;
- (IBAction)activateAddAccounts:(id)sender;
- (BOOL)completeAddAccounts;
- (IBAction)addAnotherClick:(id)sender;
- (IBAction)activateImportCB50Accounts:(id)sender;
- (BOOL)completeImportCB50Accounts;
- (IBAction)activateImportOtherAccounts:(id)sender;
- (BOOL)completeImportOtherAccounts;
- (IBAction)activateComplete:(id)sender;
- (BOOL)completeComplete;

@end

@implementation CBSetupAssistantWindowController


+ (NSString *)nibName {
	return @"SetupAssistant";
}

+ (void)runSetupAssistantWithDelegate:(id)delegate
					   didEndSelector:(SEL)didEndSelector
				   didDismissSelector:(SEL)didDismissSelector {

	CBSetupAssistantWindowController *controller;
	controller = [[self alloc] initWithDeleagte:delegate
								 didEndSelector:didEndSelector
							 didDismissSelector:didDismissSelector];
	[controller setReleaseWhenComplete:TRUE];
	[controller runSetupAssistant];
}

- (id)initWithDeleagte:(id)del
		didEndSelector:(SEL)didEnd
	didDismissSelector:(SEL)didDismiss {
	
	if (self = [super init]) {
		delegate = del;
		didEndSelector = didEnd;
		didDismissSelector = didDismiss;
		releaseWhenComplete = FALSE;
		accountAdded = FALSE;
	}
	return self;
}

- (void)dealloc {
	[[NSNotificationCenter defaultCenter] removeObserver:self];

	[cb50ImportViewController release];
	[cb50Importer release];
	[cb50ImportReplacementView release];

	[otherImportViewController release];
	[otherImporter release];
	[otherImportReplacementView release];
	
	[super dealloc];
}

- (void)windowDidLoad {
	// Taken from Adium
	// Configure our background view; it should display the image transparently where our tabView overlaps it
	[backgroundView setBackgroundImage:[NSImage imageNamed:@"transparent_coin" forClass:[self class]]];
	NSRect tabViewFrame = [tabView frame];
	NSRect backgroundViewFrame = [backgroundView frame];
	tabViewFrame.origin.x -= backgroundViewFrame.origin.x;
	tabViewFrame.origin.y -= backgroundViewFrame.origin.y;
	[backgroundView setTransparentRect:tabViewFrame];

	[progressIndicator setUsesThreadedAnimation:YES];

	// retain views that will be removed
	[cb50ImportReplacementView retain];
	[otherImportReplacementView retain];

	[accountTypesController addObjects:[[cashbox accountController] accountTypes]];
	[accountTypesController setSelectionIndex:0];
	
	[[self window] center];
	[self activateWelcome:nil];
}

- (BOOL)windowShouldClose:(id)sender {
	if ([self releaseWhenComplete]) { [self autorelease]; }
	return YES;
}

- (BOOL)releaseWhenComplete {
	return releaseWhenComplete;
}
- (void)setReleaseWhenComplete:(BOOL)flag {
	releaseWhenComplete = flag;
}

- (void)runSetupAssistant {
	[[self window] makeKeyAndOrderFront:nil];
}

- (void)finishRuningSeuptAssistant {
	[self closeWindow:nil];
	if (delegate && didEndSelector) {
		[delegate performSelector:didEndSelector withObject:self];
	}	
}

- (void)addAccount:(NSError **)error {
	Class accountType = [[accountTypesController selectedObjects] firstObject];
	NSString *name = [accountNameTextField stringValue];
	
	if (!accountType) {
		if (error) {
			NSString *errorStr = FSLocalizedString(@"You must specify a type in order to create an account.", nil);
			NSDictionary *userInfoDict = [NSDictionary dictionaryWithObject:errorStr forKey:NSLocalizedDescriptionKey];
			*error = [NSError errorWithDomain:@"CBImporterDomain" code:0 userInfo:userInfoDict];
		}
	} else if (!name || [name isEqualToString:@""]) {
		if (error) {
			NSString *errorStr = FSLocalizedString(@"You must specify a name in order to create an account.", nil);
			NSDictionary *userInfoDict = [NSDictionary dictionaryWithObject:errorStr forKey:NSLocalizedDescriptionKey];
			*error = [NSError errorWithDomain:@"CBImporterDomain" code:0 userInfo:userInfoDict];
		}
	} else {
		CBAccount *account = [[[accountType alloc] init] autorelease];
		[account setName:name];
		accountAdded = TRUE;
		
		[accountNameTextField setStringValue:@""];
		[accountTypesController setSelectionIndex:0];
	}
}

#pragma mark interface actions
// ----------------------------------------------------------------------------------------------------
// interface actions
// ----------------------------------------------------------------------------------------------------

- (IBAction)continueClick:(id)sender {
	[spinner startAnimation:nil];
	switch (selectedIndex) {
		case WELCOME_INDEX:
			if ([self completeWelcome]) {
				if (cb50ImportViewController) { [self activateImportCB50Accounts:nil]; }
				else { [self activateAddAccounts:nil]; }				
			}
			break;
		case ADD_ACCOUNTS_INDEX:
			if ([self completeAddAccounts]) { [self activateComplete:nil]; }
			break;
		case IMPORT_OHTER_INDEX:
			if ([self completeImportOtherAccounts]) { [self activateComplete:nil]; }
			break;
		case IMPORT_CB50_INDEX:
			if ([self completeImportCB50Accounts]) { [self activateComplete:nil]; }
			break;
		case COMPLETE_INDEX:
			if ([self completeComplete]) { [self finishRuningSeuptAssistant]; }
			break;
	}
	[spinner stopAnimation:nil];
}

- (IBAction)goBackClick:(id)sender {
	switch (selectedIndex) {
		case WELCOME_INDEX:
			break;
		case ADD_ACCOUNTS_INDEX:
			[self activateWelcome:nil];
			break;
		case IMPORT_CB50_INDEX:
			if (!cb50Importer) { [self activateWelcome:nil]; } // importing occurred or was canceled, just go back to beginning
			else { [cb50ImportViewController showPreviousScreen:nil]; }
			break;
		case IMPORT_OHTER_INDEX:
			if (!otherImporter) { [self activateAddAccounts:nil]; } // importing occurred or was canceled, just go back to beginning
			else { [otherImportViewController showPreviousScreen:nil]; }
			break;
		case COMPLETE_INDEX:
			if (cb50ImportViewController) { [self activateImportCB50Accounts:nil]; }
			else { [self activateAddAccounts:nil]; }				
			break;
	}	
}

- (IBAction)cancelClick:(id)sender {
	[self closeWindow:nil];
	if (delegate && didDismissSelector) {
		[delegate performSelector:didDismissSelector withObject:self];
	}
}

- (IBAction)addAnotherClick:(id)sender {
	NSError *error = nil;
	[self addAccount:&error];
	if (error) {
		[self presentError:error
			modalForWindow:[self window]
				  delegate:nil
		didPresentSelector:nil
			   contextInfo:nil];
	}
}

- (IBAction)importClick:(id)sender {
	if (otherImportViewController) {
		// if they already imported, take them back to the
		// screen that explains that they can't import again.
		// don't want them to import again and again without
		// seeing the results.
		[self activateImportOtherAccounts:nil];
	} else {		
		NSOpenPanel *openPanel = [NSOpenPanel openPanel];
		[openPanel setTitle:FSLocalizedString(@"Import", nil)];
		[openPanel setPrompt:FSLocalizedString(@"Choose", nil)];
		
		int returnCode = [openPanel runModalForDirectory:nil file:nil types:[CBImporter handledExtensions]];
		if (returnCode == NSOKButton) {
			NSString *extension = [[[openPanel filename] pathExtension] lowercaseString];
			otherImporter = [[CBImporter importerForExtension:extension] retain];
			if (otherImporter) {
				otherImportViewController = [[CBImportViewController alloc] init];
				[otherImportViewController setDelegate:self];
				[[otherImportViewController view] setFrame:[otherImportReplacementView frame]];
				[[otherImportReplacementView superview] replaceSubview:otherImportReplacementView with:[otherImportViewController view]];
				[otherImportViewController setImporter:otherImporter];
				[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willShowDifferentView:) name:CBImportViewControllerWillShowProgressViewNotification object:otherImportViewController];
				[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willShowDifferentView:) name:CBImportViewControllerWillShowStandardViewNotification object:otherImportViewController];
				[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didChangeScreen:) name:CBImportViewControllerDidChangeScreenNotification object:otherImportViewController];
				
				[otherImporter readFile:[openPanel filename]];
				[self activateImportOtherAccounts:nil];
			}
		}
	}
}

- (IBAction)moreInformationClick:(id)sender {
	[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:DONATION_URL]];
}

#pragma mark chaning views
// ----------------------------------------------------------------------------------------------------
// chaning views
// ----------------------------------------------------------------------------------------------------

- (IBAction)activateWelcome:(id)sender {
	[continueButton setTitle:FSLocalizedString(@"Continue", nil)];
	[goBackButton setEnabled:NO];
	selectedIndex = WELCOME_INDEX;
	[tabView selectTabViewItemAtIndex:selectedIndex];
}

- (BOOL)completeWelcome {
	if (!cb50ImportViewController) {
		cb50Importer = [[CB50Importer alloc] init];
		[cb50Importer readFile:[@"~/Library/Application Support/Cashbox" stringByExpandingTildeInPath]];

		// look for a critical error (i.e. no accounts)
		BOOL criticalError = FALSE;
		NSError *error;
		NSEnumerator *errorEnumerator = [[cb50Importer errors] objectEnumerator];
		while (error = [errorEnumerator nextObject]) {
			if ([error code] == CBCriticalImporterError) { criticalError = TRUE; break; }
		}
		
		if (criticalError) {
			[cb50Importer release];
			cb50Importer = nil;
		} else {
			cb50ImportViewController = [[CBImportViewController alloc] init];
			[cb50ImportViewController setDelegate:self];
			[[cb50ImportViewController view] setFrame:[cb50ImportReplacementView frame]];
			[[cb50ImportReplacementView superview] replaceSubview:cb50ImportReplacementView with:[cb50ImportViewController view]];
			[cb50ImportViewController setImporter:cb50Importer];
			[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willShowDifferentView:) name:CBImportViewControllerWillShowProgressViewNotification object:cb50ImportViewController];
			[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willShowDifferentView:) name:CBImportViewControllerWillShowStandardViewNotification object:cb50ImportViewController];
			[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didChangeScreen:) name:CBImportViewControllerDidChangeScreenNotification object:cb50ImportViewController];
		}
	}
	return YES;
}

- (IBAction)activateAddAccounts:(id)sender {
	[continueButton setTitle:FSLocalizedString(@"Continue", nil)];
	[goBackButton setEnabled:YES];
	selectedIndex = ADD_ACCOUNTS_INDEX;
	[tabView selectTabViewItemAtIndex:selectedIndex];
}

- (BOOL)completeAddAccounts {
	NSError *error = nil;
	[self addAccount:&error];
	if (error && !accountAdded) {
		[self presentError:error
			modalForWindow:[self window]
				  delegate:nil
		didPresentSelector:nil
			   contextInfo:nil];
		return NO;
	} else {
		return YES;
	}	
}

- (IBAction)activateImportCB50Accounts:(id)sender {
	[continueButton setTitle:FSLocalizedString(@"Continue", nil)];
	[goBackButton setEnabled:YES];
	selectedIndex = IMPORT_CB50_INDEX;
	[tabView selectTabViewItemAtIndex:selectedIndex];
}

- (BOOL)completeImportCB50Accounts {
	if (!cb50Importer) {
		// importing already occurred and we
		// got here with a nil importer, so it's
		// okay to continue
		return YES;
	} else {
		[cb50ImportViewController showNextScreen:nil];
		return NO;
	}
}

- (IBAction)activateImportOtherAccounts:(id)sender {
	[continueButton setTitle:FSLocalizedString(@"Continue", nil)];
	[goBackButton setEnabled:YES];
	selectedIndex = IMPORT_OHTER_INDEX;
	[tabView selectTabViewItemAtIndex:selectedIndex];	
}

- (BOOL)completeImportOtherAccounts {
	if (!otherImporter) {
		// importing already occurred and we
		// got here with a nil importer, so it's
		// okay to continue
		return YES;
	} else {
		[otherImportViewController showNextScreen:nil];
		return NO;
	}
}

- (IBAction)activateComplete:(id)sender {
	[continueButton setTitle:FSLocalizedString(@"Done", nil)];
	selectedIndex = COMPLETE_INDEX;
	[tabView selectTabViewItemAtIndex:selectedIndex];
}

- (BOOL)completeComplete {
	return YES;
}

#pragma mark import view controller notifications
// ----------------------------------------------------------------------------------------------------
// import view controller notifications
// ----------------------------------------------------------------------------------------------------

- (void)willShowDifferentView:(NSNotification *)notification {
	CBImportViewController *controller = [notification object];
	if ([controller canRespond]) {
		[goBackButton setEnabled:YES];
		[continueButton setEnabled:YES];
		[cancelButton setEnabled:YES];
	} else {
		[goBackButton setEnabled:NO];
		[continueButton setEnabled:NO];
		[cancelButton setEnabled:NO];
		[goBackButton display];
		[continueButton display];
		[cancelButton display];
	}
}

- (void)didChangeScreen:(NSNotification *)notification {
	CBImportViewController *controller = [notification object];
	if ([controller goBackButton] == CBImportViewControllerCancelButton) { [goBackButton setEnabled:NO]; }
	else if ([controller goBackButton] == CBImportViewControllerGoBackButton) { [goBackButton setEnabled:YES]; }
}

#pragma mark import view controller delegate
// ----------------------------------------------------------------------------------------------------
// import view controller delegate
// ----------------------------------------------------------------------------------------------------

- (void)importViewControllerDidCancel:(CBImportViewController *)controller {
	if (controller == cb50ImportViewController) {
		NSView *replace = [cb50ImportViewController view];
		[[replace superview] replaceSubview:replace with:cb50ImportReplacementView];
		
		[cb50Importer release];
		cb50Importer = nil;

		[[NSNotificationCenter defaultCenter] removeObserver:self name:CBImportViewControllerWillShowProgressViewNotification object:cb50ImportViewController];
		[[NSNotificationCenter defaultCenter] removeObserver:self name:CBImportViewControllerWillShowStandardViewNotification object:cb50ImportViewController];
		[[NSNotificationCenter defaultCenter] removeObserver:self name:CBImportViewControllerDidChangeScreenNotification object:cb50ImportViewController];
		[cb50ImportViewController release];
		cb50ImportViewController = nil;
	} else if (controller == otherImportViewController) {
		NSView *replace = [otherImportViewController view];
		[[replace superview] replaceSubview:replace with:otherImportReplacementView];
		
		[otherImporter release];
		otherImporter = nil;
		
		[[NSNotificationCenter defaultCenter] removeObserver:self name:CBImportViewControllerWillShowProgressViewNotification object:otherImportViewController];
		[[NSNotificationCenter defaultCenter] removeObserver:self name:CBImportViewControllerWillShowStandardViewNotification object:otherImportViewController];
		[[NSNotificationCenter defaultCenter] removeObserver:self name:CBImportViewControllerDidChangeScreenNotification object:otherImportViewController];
		[otherImportViewController release];
		otherImportViewController = nil;
	}
	[self goBackClick:nil];
}

- (void)importViewControllerHasCompletedAllScreens:(CBImportViewController *)controller {
	accountAdded = TRUE;
	// when completing, the viewController isn't released.  it's our way of knowing
	// that importing has already occurred
	if (controller == cb50ImportViewController) {
		NSView *replace = [cb50ImportViewController view];
		[[replace superview] replaceSubview:replace with:cb50ImportReplacementView];
		[cb50Importer release];
		cb50Importer = nil;
	} else if (controller == otherImportViewController) {
		NSView *replace = [otherImportViewController view];
		[[replace superview] replaceSubview:replace with:otherImportReplacementView];
		[otherImporter release];
		otherImporter = nil;
	}
	[goBackButton setEnabled:YES];
	[continueButton setEnabled:YES];
	[cancelButton setEnabled:YES];
	[self continueClick:nil];
}

- (void)importViewControllerAcceptedImport:(CBImportViewController *)controller {
	[[controller importer] importData];
}

@end
